package simulation;

import common.Constants;

/**
 * @author cwhalen
 * 
 */
public class Node {
  public float degLatTop;
  public float degLatBottom;
  public float degLonLeft;
  public float degLonRight;
  public float area;
  public float height;
  public float topLength;
  public float sideLength;
  public float bottomLength;
  public float oldTemp;
  public float newTemp;
  public float heatCoeff;
  public float sunHeat;

  public Node left, right, top, bottom;

  /**
   * Call init to initialize this node to its default temperature.
   */
  public Node(int gridSpacing) {
    float heatFactor = (float)gridSpacing / 10f;    
    this.heatCoeff = (float)gridSpacing / 12f * (heatFactor == 0 ? 1 : heatFactor) ;
  }
  
  public void init() {
    this.oldTemp = Constants.DEFAULT_CELL_TEMP;
    this.newTemp = Constants.DEFAULT_CELL_TEMP;
  }

  /**
   * @param radius radius of the Earth
   */
  private void cLengths(int radius) {
    float sepDeg = degLatTop - degLatBottom;
    this.topLength = Util.cLattitudeCircum(degLatTop, radius) / (360 / Math.abs(sepDeg));
    this.bottomLength = Util.cLattitudeCircum(degLatBottom, radius) / (360 / Math.abs(sepDeg));
    this.sideLength = Util.cTrapezoidSideLen(topLength, bottomLength, height);
  }

  /**
   * @param radius
   */
  private void cArea(int radius) {
    this.area = Util.cTrapezoidArea(topLength, bottomLength, height);
  }

  /**
   * @param radius
   */
  private void cHeight(int radius) {
    this.height = Math.abs(Util.distToEquator(degLatTop, radius) - Util.distToEquator(degLatBottom, radius));
  }

  /**
   * @param radius
   */
  public void cGeometry(int radius) {
    this.cHeight(radius);
    this.cLengths(radius);
    this.cArea(radius);
  }

  /**
   * @param sun
   */
  public void cTemp(Sun sun) {
    double radFact = sun.cRadiationFactor(degLatTop, degLatBottom, degLonLeft, degLonRight);

    this.sunHeat = (float) (heatCoeff * radFact);
    this.newTemp = (this.sunHeat + this.cNeighborHeat());
  }

  /**
   * @param globalHeatIncrease
   * @param nodes
   */
  public void cCool(float globalHeatIncrease, int nodes) {
    if (this.sunHeat == 0) {
      this.newTemp -= globalHeatIncrease / nodes;
    }
  }

  /**
   * @return
   */
  private float cNeighborHeat() {
    float totalLen = topLength + bottomLength + sideLength + sideLength;

    float l = (left != null) ? left.oldTemp : 0;
    float r = (right != null) ? right.oldTemp : 0;
    float t = (top != null) ? top.oldTemp : 0;
    float b = (bottom != null) ? bottom.oldTemp : 0;

    float result = ((sideLength / totalLen) * l) + ((sideLength / totalLen) * r) + ((topLength / totalLen) * t) + ((bottomLength / totalLen) * b);

    return result;
  }

  /**
   * 
   */
  public void swapTemp() {
    this.oldTemp = this.newTemp;
  }
}
